curl --request GET \
--url https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticalsimport requests
url = "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals")
.asString();require 'uri'
require 'net/http'
url = URI("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"totals": {
"events": 123,
"live": 123,
"openMarketCount": 123,
"totalMarketCount": 123,
"scopes": [
{
"slug": "games",
"count": 123
}
]
},
"verticals": [
{
"slug": "<string>",
"group": "sports",
"count": 123,
"live": 123,
"openMarketCount": 123,
"totalMarketCount": 123,
"competitions": [
{
"slug": "<string>",
"name": "<string>",
"season": {},
"logo": {},
"count": 123,
"live": 123,
"openMarketCount": 123,
"totalMarketCount": 123,
"scopes": [
{
"slug": "games",
"count": 123
}
]
}
],
"scopes": [
{
"slug": "games",
"count": 123
}
],
"subcategories": [
{
"slug": "<string>",
"name": "<string>",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"crypto": {
"frequencies": [
{
"slug": "5-minute",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"cadences": [
{
"slug": "5-minute",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"assets": [
{
"slug": "<string>",
"name": "<string>",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"preMarket": {
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
},
"others": {
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
}
}
]
}Nav sidebar summary — verticals → competitions → event and market counts
TWO kinds of number here, obeying TWO different rules. count / live and every chip bucket count EVENTS and equal the LENGTH of the correspondingly filtered list (see the parity paragraph below). openMarketCount / totalMarketCount count MARKETS and equal the SUM of the same-named field over that same list — never its length, and never derivable from count. ⚠️ That SUM rule holds at the ROW level (totals, vertical, competition) and NOT on the crypto chips, which carry the same two field names one level down. A chip counts the BUCKET’S OWN markets, so summing openMarketCount over /api/events?asset=btc comes out LARGER — that list returns events, and a mixed event’s ETH markets ride along. Chips reconcile upward against the crypto row instead; see the description on the chip fields themselves before writing any reconciliation against them. The SUB-TOPIC chips (subcategories) carry the same two field names and are the OTHER case: a rubric owns its events outright — one rubric per event — so the SUM rule holds there exactly as it does at the row level. What does NOT hold for them is the residual: never render “others” as vertical minus Σ chips, because retired rubrics and non-emittable slugs sit inside the vertical and under no chip. Vertical slugs are the platform-canonical vocabulary, so a new vertical appears here the moment it has data. Counts use exactly the /api/events default open-view visibility (≥1 tradeable market + listable-now floor), so every FILTERABLE bucket (vertical, competition, scope, and the crypto block’s asset/cadence/frequency chips) equals the length of the correspondingly filtered /api/events response, up to that endpoint’s pagination window (the count reflects the full matching set; a single /api/events page may return fewer rows) — this parity holds for the DEFAULT OPEN VIEW only (no ?closed=true), the same open-view scope the crypto block itself is computed over; a ?closed=true list has no matching sidebar count to compare against. The crypto block’s preMarket bucket is checked against /api/events?vertical=crypto&preMarket=true. The vertical is REQUIRED in that link and is not decoration: ?preMarket= is platform-wide by design (PRE_MARKET means the same thing in every vertical, so gating it would make ?vertical=football&preMarket=true silently empty and stop false from being a complement), so the bare form returns every vertical’s pre-market events and matches no sidebar number at all. By DEFAULT the response is render-ready: zero-count competitions and zero-count verticals are trimmed. Pass ?includeEmpty=1 for the full catalog view (every active competition, catalog-first zero rows included — a vertical appears once it has an active competition or a countable event). Counts are identical in both views. live uses the same in-play predicate as /api/events?sort=live. Cached server-side for 3 minutes (one shared cache for both views). Scope chips are data-driven per level (totals, vertical, competition); ?scope= on /api/events filters by them. Sub-topic subcategories[] chips are data-driven per VERTICAL and filter via ?subcategory=, which needs no companion ?vertical= because a rubric slug is globally unique and names its own vertical — so they obey the parity rule above unaided: a chip reading N lists N.
curl --request GET \
--url https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticalsimport requests
url = "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals")
.asString();require 'uri'
require 'net/http'
url = URI("https://core.api.dev.predictstreet.sde.adifoundation.ai/api/verticals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"totals": {
"events": 123,
"live": 123,
"openMarketCount": 123,
"totalMarketCount": 123,
"scopes": [
{
"slug": "games",
"count": 123
}
]
},
"verticals": [
{
"slug": "<string>",
"group": "sports",
"count": 123,
"live": 123,
"openMarketCount": 123,
"totalMarketCount": 123,
"competitions": [
{
"slug": "<string>",
"name": "<string>",
"season": {},
"logo": {},
"count": 123,
"live": 123,
"openMarketCount": 123,
"totalMarketCount": 123,
"scopes": [
{
"slug": "games",
"count": 123
}
]
}
],
"scopes": [
{
"slug": "games",
"count": 123
}
],
"subcategories": [
{
"slug": "<string>",
"name": "<string>",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"crypto": {
"frequencies": [
{
"slug": "5-minute",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"cadences": [
{
"slug": "5-minute",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"assets": [
{
"slug": "<string>",
"name": "<string>",
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
],
"preMarket": {
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
},
"others": {
"count": 123,
"openMarketCount": 123,
"totalMarketCount": 123
}
}
}
]
}Query Parameters
true/1 → include zero-count competitions and zero-count verticals (the full active catalog). Absent or empty → the default trimmed view. Any other unparseable value → 400 invalid_includeEmpty (same contract as the closed flag on the list endpoints).