curl --request GET \
--url https://api.agg.market/catalog/changes \
--header 'x-app-id: <api-key>'import requests
url = "https://api.agg.market/catalog/changes"
headers = {"x-app-id": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-app-id': '<api-key>'}};
fetch('https://api.agg.market/catalog/changes', 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://api.agg.market/catalog/changes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-app-id: <api-key>"
],
]);
$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://api.agg.market/catalog/changes"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-app-id", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.agg.market/catalog/changes")
.header("x-app-id", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.agg.market/catalog/changes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-app-id"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"entity": "event",
"id": "<string>",
"op": "created",
"version": 123,
"changedAt": "2023-11-07T05:31:56Z",
"venue": "<string>",
"event": {
"id": "<string>",
"venue": "<string>",
"externalIdentifier": "<string>",
"title": "<string>",
"slug": "<string>",
"status": "<string>",
"startDate": "2023-11-07T05:31:56Z",
"endDate": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"categories": [
{
"id": "<string>",
"name": "<string>"
}
],
"matched": true,
"clusterAnchorId": "<string>",
"clusterVenues": [
"<string>"
]
},
"market": {
"id": "<string>",
"venueEventId": "<string>",
"venue": "<string>",
"externalIdentifier": "<string>",
"question": "<string>",
"shortTitle": "<string>",
"status": "<string>",
"startDate": "2023-11-07T05:31:56Z",
"endDate": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"outcomes": [
{
"id": "<string>",
"label": "<string>",
"title": "<string>"
}
],
"categories": [
{
"id": "<string>",
"name": "<string>"
}
],
"matched": true,
"clusterAnchorId": "<string>",
"clusterVenues": [
"<string>"
]
}
}
],
"nextCursor": "<string>",
"hasMore": true
}{
"message": "<string>"
}{
"message": "<string>"
}{
"message": "<string>",
"code": "resync_required"
}{
"message": "<string>",
"statusCode": 429,
"code": "rate_limited",
"retryAfter": 2
}{
"statusCode": 503,
"code": "rate_limit_unavailable",
"message": "<string>",
"retryAfter": 2
}List catalog changes
Events and markets that were created, changed or deleted after since, oldest first, one item per entity with its current state (including cross-venue matching). This is the catch-up half of the catalog feed: subscribe to the WebSocket catalog channel first, then page this endpoint from your last changedAt (minus about a minute of overlap) until hasMore is false, and apply each item only when its (version, changedAt) is newer than what you hold. The SDK’s watchCatalog does all of this. Positions older than 24 hours return 410 resync_required: re-list with GET /venue-events and GET /venue-markets, then resume from the time you started that re-list.
curl --request GET \
--url https://api.agg.market/catalog/changes \
--header 'x-app-id: <api-key>'import requests
url = "https://api.agg.market/catalog/changes"
headers = {"x-app-id": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'x-app-id': '<api-key>'}};
fetch('https://api.agg.market/catalog/changes', 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://api.agg.market/catalog/changes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"x-app-id: <api-key>"
],
]);
$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://api.agg.market/catalog/changes"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("x-app-id", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.agg.market/catalog/changes")
.header("x-app-id", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.agg.market/catalog/changes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["x-app-id"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"entity": "event",
"id": "<string>",
"op": "created",
"version": 123,
"changedAt": "2023-11-07T05:31:56Z",
"venue": "<string>",
"event": {
"id": "<string>",
"venue": "<string>",
"externalIdentifier": "<string>",
"title": "<string>",
"slug": "<string>",
"status": "<string>",
"startDate": "2023-11-07T05:31:56Z",
"endDate": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"categories": [
{
"id": "<string>",
"name": "<string>"
}
],
"matched": true,
"clusterAnchorId": "<string>",
"clusterVenues": [
"<string>"
]
},
"market": {
"id": "<string>",
"venueEventId": "<string>",
"venue": "<string>",
"externalIdentifier": "<string>",
"question": "<string>",
"shortTitle": "<string>",
"status": "<string>",
"startDate": "2023-11-07T05:31:56Z",
"endDate": "2023-11-07T05:31:56Z",
"createdAt": "2023-11-07T05:31:56Z",
"outcomes": [
{
"id": "<string>",
"label": "<string>",
"title": "<string>"
}
],
"categories": [
{
"id": "<string>",
"name": "<string>"
}
],
"matched": true,
"clusterAnchorId": "<string>",
"clusterVenues": [
"<string>"
]
}
}
],
"nextCursor": "<string>",
"hasMore": true
}{
"message": "<string>"
}{
"message": "<string>"
}{
"message": "<string>",
"code": "resync_required"
}{
"message": "<string>",
"statusCode": 429,
"code": "rate_limited",
"retryAfter": 2
}{
"statusCode": 503,
"code": "rate_limit_unavailable",
"message": "<string>",
"retryAfter": 2
}Integration guide
- Before you call: Understand events, markets, and outcomes.
- Workflow: Keep a local catalog in sync.
- Next: Subscribe to live orderbook updates.
Authorizations
Your application ID. Required on app-tier and user-tier routes. Omitted on routes that authenticate with x-app-api-key only.
Query Parameters
Start of the walk (ISO). Required unless cursor is sent. At most 24 hours ago — older positions get 410 and a full resync via the list endpoints.
nextCursor from the previous page. Takes precedence over since.
1 <= x <= 500kalshi, polymarket, limitless, predict, pred, tiprun, myriad, hyperliquid, novig, prophetx, betdex event, market Response
200