{"openapi":"3.1.0","info":{"title":"Front Row Database API","version":"1.0.0","description":"A live price database for tickets, tracked across StubHub, SeatGeek, Vivid Seats & TickPick. Reading is keyless. Curating a collection and submitting new records need an API key."},"servers":[{"url":"https://frontrowtickets.xyz"}],"tags":[{"name":"read","description":"Keyless. Query the database."},{"name":"curate","description":"Key required. Save records; we keep pricing them."},{"name":"grow","description":"Key required. Submit records we don't hold yet."}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key"}}},"paths":{"/v1":{"get":{"operationId":"discovery","summary":"Everything, machine-readable.","description":"The entry point. An agent that finds this URL can reach the whole dataset without ever reading these docs — which is the point.","tags":["read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}}}},"/v1/schema":{"get":{"operationId":"schema","summary":"Field-level types for every record.","description":"Bind to the data without guessing what a field means or whether it can be null.","tags":["read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}}}},"/v1/tickets":{"get":{"operationId":"search","summary":"Search and browse every ticket we track.","description":"Token-AND search across title, brand, ticket reference and colorway. Priced records come first — an unpriced row is the least useful answer to \"what does this cost\". Also served at /v1/items, which is identical on every site in the fleet, so one client works against all of them.","tags":["read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}},"parameters":[{"name":"q","in":"query","required":false,"description":"Search text. Tokens are ANDed.","schema":{"type":"string"}},{"name":"brand","in":"query","required":false,"description":"Exact brand match.","schema":{"type":"string"}},{"name":"source","in":"query","required":false,"description":"Marketplace the row came from.","schema":{"type":"string"}},{"name":"priced","in":"query","required":false,"description":"true — only records carrying a live price.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"1–100, default 20.","schema":{"type":"string"}},{"name":"offset","in":"query","required":false,"description":"Paging offset.","schema":{"type":"string"}}]}},"/v1/tickets/{slug}":{"get":{"operationId":"record","summary":"One ticket.","description":"404s with a JSON body if the slug is unknown. Cite the `url` field — it's the canonical page for that record.","tags":["read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}]}},"/v1/tickets/{slug}/history":{"get":{"operationId":"history","summary":"The time series behind the current price.","description":"Every point is a real listing observed at that timestamp. This is what a price chart is made of, and what an estimate is not.","tags":["read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"1–1000, default 200.","schema":{"type":"string"}}]}},"/v1/trending":{"get":{"operationId":"trending","summary":"What's moving now.","description":"What's moving now.","tags":["read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}},"parameters":[{"name":"limit","in":"query","required":false,"description":"1–100, default 6.","schema":{"type":"string"}}]}},"/v1/stats":{"get":{"operationId":"stats","summary":"Dataset size and freshness.","description":"So an agent can judge our coverage honestly instead of assuming it. `queryable` is every row this API can return; `priced` is how many carry a live price; `contributed` is what agents have added through /v1/track.","tags":["read"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}}}},"/v1/key":{"get":{"operationId":"key","summary":"What your key can do.","description":"Quota, collection cap, and how much of it you've used. Call it once at startup and plan, rather than probing until something 429s.","tags":["curate"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"No key. Reading is keyless; writing is not."},"403":{"description":"Key is valid but this plan can't write."},"429":{"description":"Rate limited. See Retry-After."}},"security":[{"ApiKeyAuth":[]}]}},"/v1/collection":{"get":{"operationId":"collection_get","summary":"Your collection, priced live.","description":"Not a bookmark list. We keep pricing everything in it, and `status` tells you whether the target you set has been hit — so an agent can poll this one endpoint and know when to tell its human to act.","tags":["curate"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"No key. Reading is keyless; writing is not."},"403":{"description":"Key is valid but this plan can't write."},"429":{"description":"Rate limited. See Retry-After."}},"security":[{"ApiKeyAuth":[]}]},"post":{"operationId":"collection_post","summary":"Save one, and watch its price.","description":"If we don't track the URL yet, saving it also queues it for ingest — so you never have to ask whether we've heard of the thing. Either we can price it now, or we go and learn it.","tags":["curate"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"No key. Reading is keyless; writing is not."},"403":{"description":"Key is valid but this plan can't write."},"429":{"description":"Rate limited. See Retry-After."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"Marketplace listing URL. Required."},"targetPrice":{"type":"number","description":"Tell us when it drops to this. Optional."}}}}}},"security":[{"ApiKeyAuth":[]}]}},"/v1/collection/{id}":{"delete":{"operationId":"collection_delete","summary":"Remove one.","description":"Remove one.","tags":["curate"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"No key. Reading is keyless; writing is not."},"403":{"description":"Key is valid but this plan can't write."},"429":{"description":"Rate limited. See Retry-After."}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[{"ApiKeyAuth":[]}]}},"/v1/track":{"post":{"operationId":"track","summary":"Grow the database: submit a ticket we don't hold.","description":"The catalog is finite and the world is not. Hand us a URL from StubHub, SeatGeek, Vivid Seats & TickPick and we fetch it, price it, and serve it back through this same API — usually within a few minutes. Submissions run through our own scraper, so what you get back is a first-class record, not a copy of what you sent. Idempotent: re-submitting a URL we already track is a no-op.","tags":["grow"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"No key. Reading is keyless; writing is not."},"403":{"description":"Key is valid but this plan can't write."},"429":{"description":"Rate limited. See Retry-After."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"Marketplace listing URL. Required."}}}}}},"security":[{"ApiKeyAuth":[]}]},"get":{"operationId":"track_get","summary":"Did my submission land?","description":"Keyless, so you can hand the polling to a cheaper unauthenticated worker.","tags":["grow"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Rate limited. See Retry-After."}},"parameters":[{"name":"url","in":"query","required":false,"description":"The URL you submitted.","schema":{"type":"string"}}]}}}}