Arbitrage history
curl --request GET \
--url https://api.probsights.com/v1/arbitrage/history \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.probsights.com/v1/arbitrage/history"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.probsights.com/v1/arbitrage/history', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"items": [
{}
],
"total": 123,
"offset": 123,
"limit": 123,
"has_more": true,
"first_seen_at": "<string>",
"last_seen_at": "<string>",
"opportunity": {},
"event_id": "<string>",
"event_title": "<string>",
"outcome_key": "<string>",
"label": "<string>",
"timestamp": "<string>",
"market_type": "<string>",
"interval_code": "<string>",
"resolution_time": "<string>",
"kalshi_event_ticker": "<string>",
"polymarket_event_slug": "<string>",
"kalshi": {},
"polymarket": {},
"buy_yes_market": "<string>",
"buy_no_market": "<string>",
"gross_cents": 123,
"fee_cents": 123,
"net_cents": 123,
"roi_percent": 123,
"executable_size": 123,
"max_profit_dollars": 123,
"yes_leg": {},
"no_leg": {},
"orderbook": {},
"locked": true
}Arbitrage
Arbitrage history
Paged historical arbitrage opportunities recorded by the background scanner.
GET
/
v1
/
arbitrage
/
history
Arbitrage history
curl --request GET \
--url https://api.probsights.com/v1/arbitrage/history \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.probsights.com/v1/arbitrage/history"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.probsights.com/v1/arbitrage/history', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"items": [
{}
],
"total": 123,
"offset": 123,
"limit": 123,
"has_more": true,
"first_seen_at": "<string>",
"last_seen_at": "<string>",
"opportunity": {},
"event_id": "<string>",
"event_title": "<string>",
"outcome_key": "<string>",
"label": "<string>",
"timestamp": "<string>",
"market_type": "<string>",
"interval_code": "<string>",
"resolution_time": "<string>",
"kalshi_event_ticker": "<string>",
"polymarket_event_slug": "<string>",
"kalshi": {},
"polymarket": {},
"buy_yes_market": "<string>",
"buy_no_market": "<string>",
"gross_cents": 123,
"fee_cents": 123,
"net_cents": 123,
"roi_percent": 123,
"executable_size": 123,
"max_profit_dollars": 123,
"yes_leg": {},
"no_leg": {},
"orderbook": {},
"locked": true
}Paged feed of every arbitrage opportunity episode recorded by the always-on
background scanner, newest first. Repeated detections of the same opportunity
extend an existing episode instead of creating a duplicate.
This is the endpoint the Dashboard arbitrage
table reads from, and the only place
Use
min_net_cents is applied server-side across
all recorded opportunities (not just the rows currently loaded in the UI).
Returns a page envelope: {items, total, offset, limit, has_more}.
Preview access (anonymous visitors, free accounts, unauthenticated API keys)
returns the first opportunity unmasked and locks the rest — see
Preview masking.
Request
https://api.probsights.com/v1/arbitrage/history
Query parameters
integer
default:"50"
Max items per page (1–100).
integer
default:"0"
Zero-based page offset.
string
Filter by interval:
5m, 15m, 1h, 24h, or 1w. Omit for all.string
Filter by
crypto or sports.number
default:"0"
Minimum net profit after fees, in cents. Applied server-side over the full
history in the database, independent of the loaded page.
string
ISO-8601 timestamp. Keep episodes last seen at or after this.
string
ISO-8601 timestamp. Keep episodes first seen at or before this.
Response
Fieldsopinion_market_id and opinion are null for BTC interval scope and
omitted. All monetary fields are null for locked (preview) rows.
array
List of opportunity episodes, newest first.
int
Total episodes matching the filters (before paging).
int
Zero-based offset used for this page.
int
Page size used for this request.
boolean
Whether another page exists after this one.
Episode
string
First timestamp this opportunity was observed.
string
Most recent timestamp this opportunity was observed.
object
The detected opportunity object.
Opportunity
string
Canonical event identifier (e.g.
btc-updown-15m-1789273800).string
Human-readable event title.
string
Outcome bucket key (e.g.
btc_15m).string
Short display label (e.g.
BTC 15m).string
Opportunity snapshot time.
string
Market type, currently
binary.string
Interval for the window when applicable.
string
Window settlement time.
string
Matching Kalshi event ticker, when available.
string
Matching Polymarket event slug, when available.
object
Kalshi leg snapshot:
market_ticker, yes_ask, no_ask, volume,
volume_24h, open_interest.object
Polymarket leg snapshot:
condition_id, yes_token_id, no_token_id,
yes_ask, no_ask, volume, liquidity.string
Venue to buy YES (
kalshi or polymarket).string
Venue to buy NO.
number
Gross edge in cents before fees.
number
Estimated taker fees in cents.
number
Net edge after fees in cents.
number
Return on capital for the paired legs.
number
Number of contracts executable at the shown edge.
number
Maximum profit in dollars at the executable size.
object
Execution leg:
market, identifier, book_side.object
Execution leg:
market, identifier, book_side.object
Present only when orderbook depth is captured for the episode.
boolean
true for masked preview rows. See below.Examples
15-minute opportunities with min edge
curl -H "X-API-Key: YOUR_API_KEY" \
"https://api.probsights.com/v1/arbitrage/history?min_net_cents=2&interval_code=15m&limit=20"
import requests
response = requests.get(
"https://api.probsights.com/v1/arbitrage/history",
headers={"X-API-Key": "YOUR_API_KEY"},
params={"min_net_cents": 2, "interval_code": "15m", "limit": 20},
)
page = response.json()
const response = await fetch(
"https://api.probsights.com/v1/arbitrage/history?min_net_cents=2&interval_code=15m&limit=20",
{ headers: { "X-API-Key": "YOUR_API_KEY" } }
);
const page = await response.json();
Paginate through the feed
curl -H "X-API-Key: YOUR_API_KEY" \
"https://api.probsights.com/v1/arbitrage/history?limit=100&offset=100"
has_more to keep paging; total is the filtered count. Keep limit fixed
across pages for stable offset math.
Preview masking
Without a paid entitlement the scanner’s history is masked server-side: the opportunity shown first islocked: false with full prices and net_cents, and
every other row is locked: true with net_cents: null and both venue asks
removed. A Trader subscription — see Authentication —
unlocks the full feed.
Fee model
Arb legs are modeled as taker orders (buying at the ask):| Exchange | Formula (1 contract) | Rounding |
|---|---|---|
| Kalshi | 0.07 × price × (1 − price) | Round up to next cent |
| Polymarket (crypto) | 0.07 × price × (1 − price) | Round to 5 dp; min charge 0.00001 |