Chapter 17 — Building Inventory: From Vendor API to Tables
Attend onboarding guide · ~8 min read · ↑ Back to contents
Chapter 9 said Attend keeps its own copy of the seats and rebuilds it every ~20 minutes. This chapter opens that box: how the copy is actually built, from a vendor API call down to the rows in Attend's database. We'll use Ticketmaster (the reference vendor) throughout.
Two calls to one API
Everything starts with two calls to the same Ticketmaster inventory API. They're the same endpoint asked two different ways — the second just requests more detail.
Call 1 — section and price level. For each section: how many seats it has, and the pricing available — i.e. which price code × ticket type code equals which amount (Chapter 7). At this point Attend knows the shape and the money, but not individual seats.
Call 2 — seat level. The same API, now with the summary flag off (summary_flag: N),
returns seat-by-seat detail. For each section it gives a compact row:
section, row, first seat, last seat, total seats, seat increment, aisle indicator, class name, price code, quality
A few of those fields are worth a note:
- Seat increment — always 1 in practice (seats numbered 1, 2, 3 …). Attend has never seen otherwise, but the field exists.
- Aisle indicator —
0none ·1left seat is the aisle ·2right seat is the aisle ·3both. - Quality — captured but not used yet; added in v3 in case it's ever useful for sorting.
Not "filtering." It's tempting to read Call 2 as narrowing Call 1, but it's the opposite — it's asking for more data. Normally Attend requests all sections, not a subset.
In Ticketmaster's terms both calls are get_avail_seats: Call 1 uses summary_flag: Y (the
section/price summary), and Call 2 (this one) uses summary_flag: N for the per-seat detail — its
response carries a seat_header listing exactly the fields above — section_name, row_name, first_seat, last_seat, num_seats, seat_increment, class, price_level, price_code, quality, aisle_indicator.
Where it lands: the raw inventory tables
Calls 1 and 2 are reshaped into a small set of raw tables. "Raw" is the key word — these hold no business logic; they're a faithful copy of vendor data, and they look the same for every vendor (each vendor's service flattens its own API into this shape, so the rest of the system never cares who the vendor is).
| Table | What it holds |
|---|---|
tbl_seats | the individual seats |
tbl_prices | the pricing rows |
tbl_seat_price_mapping | which price code each seat has |
tbl_sections | the sections themselves — per-section seat counts / shape from Call 1 |
One detail that trips people up reading the schema: a seat's price code lives in
tbl_seat_price_mapping, not on the seats row — it was split out to support TM Host's
seat/price model. If you expected price code on the seat itself, that's why it isn't there.
The optional third call: "full price code"
There's an optional third call — a separate event_price_info command (flag-gated by
disablePriceInfoForBuild), not another get_avail_seats. On its own, a price code (C) and a
ticket type code (76) combine into a full price code (think C76, or A + 1 → A1). It fills
exactly one column and nothing else depends on it — the two mandatory calls already build everything.
Why optional? Cost. Adding it bumps inventory building from two API calls to three — roughly +50% API usage. So it sits behind a config flag and can be switched off per team. Half the company doesn't use the full price code; it's narrow and rarely touched in the code.
Why the stinginess: rate limits
That cost matters because the vendor rate-limits Attend — Ticketmaster's cap is ~120 calls per
minute (TM advertises the live quota in response headers — rate-limit-available-count /
quota-rate-limit — so the limit is read at runtime, not a hard-coded number). Two refinements
sharpen the picture:
- Purchase APIs are no longer rate-limited. Only the side APIs — customer lookup, get inventory — carry the cap, so a checkout rush can't hit the wall. The biggest risk remains the customer lookup call.
- The limit is per DSN, and one DSN = one client = one TM database. The Knicks and Rangers share a DSN (one client); the Diamondbacks and Yankees don't (two databases, independent limits). The sobering case is Live Nation: one company, one database — every LN venue in the country shares a single DSN, which is why optional API calls plus a major LN on-sale make people nervous.
So Attend leans on caching and careful query structure rather than an elaborate limiter, and keeps optional work (like the full price code, or pre-filling a signup form from the vendor) behind flags it can disable for a team that starts hitting the ceiling. Dashboard-side build jobs also check the remaining limit and pause-and-retry when they hit it; for raw fan traffic spikes (an email-blast on-sale), a queueing vendor called Crowd Handler funnels visitors in gradually instead of letting them all land at once.
Example: to build the Warriors' inventory for a game, Attend calls the TM inventory API once for section/price totals, once more for seat-by-seat rows, fills
seats/prices/seat_price_mapping, and — only if the flag is on — makes a third call to record full price codes. Twenty minutes later, it does it all again to stay current.
🛠️ Where this runs: the build orchestration lives in the admin/config backend (cortex-backend) — it makes the vendor calls and writes the shared
tbl_*inventory tables (on a cron). The fan backend (flex-v3-backend) only reads them; its own TM service is just auth / customer lookup.
Recap
- Inventory is built from two calls to one vendor API: Call 1 = section + price level, Call 2 = seat-by-seat detail (with seat increment, aisle indicator, class name, price code).
- It lands in raw, business-logic-free tables (
tbl_seats,tbl_prices,tbl_seat_price_mapping,tbl_sections) that look the same for every vendor. - A seat's price code lives in
seat_price_mapping, moved off the seat row to support TM Host. - A third "full price code" call is optional (+50% API usage) and flag-controlled, because the vendor rate-limits Attend — ~120/min per DSN (one DSN = one client database; all of Live Nation shares one). Purchase APIs are exempt; Crowd Handler queues fan traffic spikes.