> ## Documentation Index
> Fetch the complete documentation index at: https://docs.graphadvocate.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Prediction-market cross-venue spread

> One paid endpoint that JOINs Polymarket and Limitless on a topic. Per-pair yes-mid spread, arbitrage direction, and the JOIN single-venue passthroughs structurally can't return.

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

| Endpoint                  |   Cost | Returns                                                                                                                                                                   |
| ------------------------- | -----: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /predmarket/spread` | \$0.05 | Same-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

```bash theme={null}
curl -X POST 'https://graphadvocate.com/predmarket/spread' \
  -H 'Content-Type: application/json' \
  -d '{"topic": "sol", "limit": 5}'
```

Response:

```json theme={null}
{
  "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[]`:

| Status                         | Meaning                                                                                                                                 |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `ok`                           | One or more pairs survived semantic filter                                                                                              |
| `no_semantic_match`            | Both venues had binary markets but none pair up semantically — the topic overlaps by keyword but the markets are about different events |
| `limitless_multi_outcome_only` | Polymarket has binary markets, Limitless only has NegRisk multi-outcome — binary spread is undefined                                    |
| `polymarket_only`              | Limitless had no markets for this topic                                                                                                 |
| `limitless_only`               | Polymarket had no markets for this topic                                                                                                |
| `no_matches`                   | Neither 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`](https://github.com/PaulieB14/graph-advocate/blob/main/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.
