Market data

aggKey

Optional fetch filter for rows whose key converges. Which id to store is on the Ids page.

aggKey is an optional fetch filter. sufwan-local-test computes it at discovery from that venue's own data, and you pass the string back unchanged to fetch the rows that share it. Which id to store is Ids.

It appears on both objects: VenueEvent.aggKey (the event, e.g. a game) and VenueMarket.aggKey (a market within it, e.g. a spread line).

Using it

Read aggKey off a market or event, then pass it back as a filter. The parameter accepts one key or several, and combines with the other filters (venue, status, …). Your app's venue and category visibility still applies.

SDK
import { createAggClient } from "@agg-build/sdk";

const client = createAggClient({
  baseUrl: "https://api.t.sufwankhalid.com",
  appId: "YOUR_APP_ID",
});

const { data } = await client.getVenueEvents({
  aggKey: "agg_nba_nyk_sas_260610",
});

List venue events. A market key uses the same aggKey parameter on List venue markets.

ResourceAPI Reference
Event-level keys, such as agg_nba_nyk_sas_260610List Venue Events
Market-level keys, such as agg_nba_nyk_sas_260610_sp_nyk_m10p5List Venue Markets

Use the event key for every venue's version of the same event, the market key for the exact same contract including line, period and window.

What it converges

The key is computed from each venue's own data, so how far it converges depends on the family.

It is guaranteed identical across venues where every venue exposes the same normalizable inputs: sports head-to-head (canonical league and team codes plus the game date), crypto up/down, and central-bank rate decisions (institution code plus meeting day). Two rows from different venues sharing a non-null key in those families are the same contract — same line, same period, same window.

Dated outcomes — elections, "by when" questions, token launches — are derived from whatever the venue publishes: a human-readable slug where there is one, a ticker where there is not, and a date segment from that venue's own resolution timestamp. Two venues listing the same question routinely produce different keys, so use the matched cluster for that family.

FamilyPrefixVenues emitting itConverges?
Sports head-to-headagg_{league}_…kalshi, limitless, novig, polymarket, predictGuaranteed
Crypto up/downagg_ud_kalshi, limitless, polymarket, predictGuaranteed
Central-bank rate decisionagg_cb-hyperliquid, kalshi, limitless, myriad, polymarket, predictGuaranteed
Crypto price / thresholdagg_px_hyperliquid, kalshiBest-effort
Index / equity thresholdagg_idx_kalshiBest-effort
FX over/underagg_fx_kalshiBest-effort
Dated outcomeagg_{subject}_{YYMMDD}every slug-bearing venueNo

A key carried by only one venue is usually not a convergence failure — most of the time only one venue lists that game or window. The guarantee is conditional: if two venues list the same contract, their keys agree.

When it's null

null means "no canonical key". It is not an error and does not mean the market is unmatched — those rows still carry their counterparts on matchedVenueMarkets[].

A market is keyed only when the key fully identifies the contract; see Sports market suffixes for exactly which do. Player props, individual strikes of a multi-strike ladder, and long-tail venue-specific propositions return null even when their parent event has a key. Expect null far more often on markets than on events, and design for it rather than treating it as a gap.

Do you need to parse it?

Almost never. Every fact you might read out of the string is already a typed field, and those fields are the supported contract — the segment grammar is not.

What you needRead thisParse?
Every venue's row for a contract you holdpass aggKey back as a filter, verbatimNo
Which rows are the same event or marketmatchedVenueEvents[], matchedVenueMarkets[]No
Teams, league, kickofftitle, sport, gameStartTimeNo
The line's numeric valuelineValueNo
The scope (half, quarter, set, innings)periodNo
Moneyline vs spread vs total vs propsportsMarketTypeNo
Which tab a market belongs inmarketGroupNo
Ordering within a tabsectionRank, lineValueNo
One spread/total ladder card with a line selectorfamily key derived from aggKeyYes — the only case

Building a sports detail page takes exactly one parse: the ladder family key in Grouping a line ladder. If you are reaching into the key for anything else, the field you want already exists.

Format

A key is the agg_ prefix followed by _-joined segments. Dates are YYMMDD (sports local date; daily markets) or a compact UTC instant (sub-daily intraday markets). Decimals use p (2p5 = 2.5). A future format revision will use a new prefix (e.g. aggk2_), so agg_ is your version guard.

FamilyFormatExample
Sports head-to-headagg_{league}_{teamA}_{teamB}_{YYMMDD}[{suffix}] — teams sorted; canonical per-league codes (NA tricodes, soccer country codes, folded surnames for tennis/UFC/esports); some competitions collapse to one token, e.g. FIBA regional qualifiers → fibaqagg_nba_nyk_sas_260610, agg_fifwc_bih_che_260618, agg_wta_eala_paolini_260706
Crypto up/downagg_ud_{asset}_{interval}_{startUTC} — sub-daily carries the window-start instant, daily (1d) the day onlyagg_ud_btc_1h_260610T1500, agg_ud_btc_1d_260610
Crypto price / thresholdagg_px_{asset}_{kind}_{instantUTC}agg_px_btc_15m_260610T0600
FX over/underagg_fx_{pair}_{kind}_{instantUTC}see live responses
Index / equity thresholdagg_idx_{symbol}_{kind}_{instantUTC}see live responses
Central-bank rate decisionagg_cb-{bank}_{YYMMDD} — the cb- namespace is deliberate: a bare agg_fed_{YYMMDD} would collide with the rate-level ladder already on that keyagg_cb-fed_260916
Dated outcomeagg_{normalized-subject}_{resolutionDate}agg_us-recession-2026_261231

Sports market suffixes

The market key is the event key plus a suffix. A full-game two-way moneyline carries no suffix — its market key is the event key. This is the complete set.

MarketSuffixExample
Moneyline — full game, 2-way singlenoneagg_ncaaf_cha_cita_260905
Moneyline — decomposed leg or draw_ml_{team}, _ml_drawagg_afl_ade_bul_260905_ml_ade
Moneyline — period scoped_{period}_ml, _{period}_ml_{team}, _{period}_ml_drawagg_bra2_juv_lon_260901_1h_ml_juv
Spread_sp_{team}_{m|p}{line}[_{period}]agg_arg_aae_cas_260904_sp_aae_m1p5
Total — whole match_tot_{line}[_{period}]agg_arg_aae_cas_260904_tot_0p5_1h
Total — corners_tot_corners_{line}[_{period}]agg_arg_aae_cas_260904_tot_corners_10p5
Total — one team_tot_team_{team}_{line}[_{period}]agg_arg_aae_cas_260904_tot_team_aae_0p5
Total — one team's corners_tot_team_{team}_corners_{line}agg_arg_aae_cas_260904_tot_team_aae_corners_2p5
Correct score_cs_{teamA}{scoreA}_{teamB}{scoreB} — teams sorted, each followed by its own scoreagg_arg_aae_cas_260904_cs_aae0_cas0
Both teams to score_btts[_{period}]agg_arg_aae_cas_260904_btts_1h
Team to advance_adv (2-outcome single), _adv_{team} (decomposed legs)agg_lec_ame_mon_260902_adv
UFC — goes the distance_distagg_ufc_acosta_blaydes_260912_dist
UFC — method of ending_mend_{method}agg_ufc_acosta_blaydes_260912_mend_kotko
UFC — method of victory_mvic_{method}_{fighter}agg_ufc_acosta_blaydes_260912_mvic_kotko_acosta
UFC — round of victory_vicrnd_{round}_{fighter}kalshi-only, so it groups rather than converges

{method} is a closed set: kotko, sub, dec, draw.

Full-game and full-match scopes carry no period token. Every other scope is the period value with non-alphanumeric characters removed (set_1 → set1, first_5_innings → first5innings), trailing for spread/total/BTTS and prefixed for moneyline.

Spread lines carry a leg token: m{line} when the named team gives points, p{line} when it receives them — _sp_cha_m19p5, not _sp_cha_19p5. The stored lineValue sign is a venue label, not an orientation. Code that strips a line with a bare _\d+p\d+ pattern stops matching spread keys — silently, producing one card per line instead of one ladder.

Marker tokens are not unique

A team code can be spelled exactly like a suffix marker. Tottenham is tot, Sporting is sp, Malmö is ml, and all three are live:

KeyWhat it is
agg_epl_eve_tot_260912_ml_totEverton vs Tottenham — Tottenham's moneyline leg
agg_atc_sp_wol_260906_sp_sp_m1p5Sporting vs Wolves — Sporting −1.5
agg_ptc_ml_vlm_260830_tot_team_ml_corners_2p5Malmö's corners total

Never split on the first _sp_, _tot_ or _ml_. Splitting agg_atc_sp_wol_260906_sp_sp_m1p5 on its first _sp_ yields agg_atc_sp — no opponent, no date — which collides with every other Sporting fixture. Anchor on the _YYMMDD token: it ends every event key, and markers only ever appear after it.

const DATE = /_\d{6}(?=_|$)/;

// Everything up to and including the date token — the event base.
const eventBase = (aggKey) => {
  const m = DATE.exec(aggKey);
  return m ? aggKey.slice(0, m.index + m[0].length) : aggKey;
};

Grouping a line ladder

One card with a line selector, unioned across venues — the only supported structural read of the key. Uses the eventBase helper above, and gates on sportsMarketType: neither rule is safe applied to the other type.

const familyKey = (market) => {
  const base = eventBase(market.aggKey);

  // Both legs of one symmetric spread → one family. They name DIFFERENT teams
  // (…_sp_arg_m1p5 and …_sp_che_p1p5 are the same line).
  if (market.sportsMarketType === "spread") return `${base}_sp`;

  // Drop the trailing line and optional period token. What remains keeps
  // subjects apart: …_tot, …_tot_team_arg, …_tot_corners.
  if (market.sportsMarketType === "total")
    return base + market.aggKey.slice(base.length).replace(/_\d+(p\d+)?(_[a-z0-9]+)?$/, "");

  return market.aggKey;
};

Both rules drop the period, so take it from the period field and put it in your group key alongside the family. Order totals by lineValue. Order spreads by |lineValue|, taking the side of the axis from the m/p token — polymarket stores spreads negative while kalshi, novig and predict store them positive, so sorting on the signed value interleaves the two halves of one ladder.

On this page