Skip to main content
One x402 endpoint for cross-venue prediction-market arbitrage. Polymarket has its own public API. Limitless has its own. Neither can answer “where do these two markets disagree?” in a single call — that’s the JOIN Graph Advocate assembles.

What you get

EndpointCostReturns
POST /predmarket/spread$0.05Same-topic markets paired across Polymarket + Limitless, per-pair yes-mid spread (bps), arbitrage direction. JOIN single-venue passthroughs structurally can’t return
Per-call payment in USDC on Base via x402. No subscription, no API key, no free tier.

Why cross-venue over single-venue

Polymarket’s Gamma API is public and free. Limitless’s REST search is public and free. A consuming agent could call both and diff in code — but every agent then re-implements the same matching:
  • Pull candidate markets from each venue by topic keyword
  • Normalize the yes-side price from each venue’s response shape (Polymarket uses JSON-encoded outcomePrices, Limitless uses a prices: [yes, no] array)
  • Pair candidates by closest-price-match (titles rarely overlap word-for-word)
  • Compute spread in basis points and emit arbitrage direction
Graph Advocate does it once. The cross-venue /spread endpoint is the defensible play: passthrough APIs return one venue at a time and can’t JOIN. As more prediction-market venues come online, the JOIN gets more valuable, not less.

Sample request

curl -X POST 'https://graphadvocate.com/predmarket/spread' \
  -H 'Content-Type: application/json' \
  -d '{"topic": "sol", "limit": 5}'
Response:
{
  "topic_keyword": "sol",
  "status": "ok",
  "polymarket_candidates": 1,
  "limitless_candidates": 5,
  "limitless_binary_candidates": 4,
  "semantic_rejections": 3,
  "pairs": [
    {
      "polymarket_slug": "will-the-price-of-solana-be-above-70-on-june-15",
      "polymarket_question": "Will the price of Solana be above $70 on June 15?",
      "polymarket_yes_mid": 0.265,
      "limitless_condition_id": "0x...",
      "limitless_slug": "sol-up-or-down-15-min",
      "limitless_title": "SOL Up or Down - 15 Min",
      "limitless_yes_mid": 0.59,
      "semantic_match_score": 0.111,
      "spread_yes_polymarket_minus_limitless": -0.325,
      "spread_bps": -3250,
      "arbitrage_direction": "long-limitless-short-polymarket"
    }
  ],
  "agent_note": "Pairs filtered by semantic content-word overlap + negation consistency, then ranked by absolute spread. semantic_match_score is Jaccard on content words (0-1). Verify same-condition resolution before sizing — Polymarket and Limitless markets on the same topic often have different time horizons."
}
How to use it. spread_bps is the basis-point gap on the yes-side mid. arbitrage_direction collapses the signal into one of:
  • long-polymarket-short-limitless — Polymarket is more expensive; if the two markets resolve identically, sell Polymarket and buy Limitless.
  • long-limitless-short-polymarket — Limitless is more expensive; reverse.
  • tight — within ±200bps; no edge after fees.
semantic_match_score is a 0-1 Jaccard score on shared content words between the two market titles (after stopword removal). Pairs below threshold (0.10) are rejected outright. A higher score doesn’t guarantee same-event resolution — it only signals overlap by content words. Verify resolution dates + outcome definitions before sizing. The status field tells you which venues had candidates so you don’t waste a call interpreting an empty pairs[]:
StatusMeaning
okOne or more pairs survived semantic filter
no_semantic_matchBoth venues had binary markets but none pair up semantically — the topic overlaps by keyword but the markets are about different events
limitless_multi_outcome_onlyPolymarket has binary markets, Limitless only has NegRisk multi-outcome — binary spread is undefined
polymarket_onlyLimitless had no markets for this topic
limitless_onlyPolymarket had no markets for this topic
no_matchesNeither venue matched; broaden the keyword

Honest coverage note

Polymarket and Limitless cover mostly disjoint market sets today. Polymarket leans US politics, sports, current events, and long-horizon crypto price thresholds. Limitless leans short-horizon (5-15 min) up/down price markets and multi-outcome categorical markets. Practically, the topics where both venues have semantically-aligned binary markets are narrow — often just crypto majors (BTC, ETH, SOL) on similar time horizons. When the endpoint returns no pairs but shows nonzero candidates, that’s the signal: the topic exists on both venues but the actual markets aren’t comparable. That’s still useful intelligence (one less venue to check) — it just isn’t an arbitrage opportunity. Verify before sizing: even when a pair passes the semantic filter, time horizons can differ (e.g. Polymarket “will SOL be above $70 by June 15” vs Limitless “SOL up/down in 15 min” — both involve SOL but are different bets). Always check resolution date + outcome definitions before treating spread as arbitrage.

How it differs from /kalshi-polymarket/spread

Same JOIN-shaped value-add, different venue pair:
  • /predmarket/spread — Polymarket ↔ Limitless (Base-native CTF prediction market, public REST search, no auth required)
  • /kalshi-polymarket/spread — Polymarket ↔ Kalshi (US-regulated, public REST)
Topic coverage skews differently. Limitless leans crypto / AI / tech. Kalshi leans US politics / sports / economics. Polymarket overlaps everything. Pick the endpoint by the venue pair you actually want to arbitrage.

Routing for free first

If you want to inspect the routing for free, send a plain-English question to POST / (A2A JSON-RPC) and Graph Advocate will name the right predmarket/* endpoint and hand back the exact paid curl — without charging.

Source

limitless_intel.py — the cross-venue search + closest-price-match pairing logic and how it fetches from Polymarket’s Gamma API and Limitless’s REST search.