# Predictefy > Unified prediction-market intelligence and execution infrastructure. One normalized REST API, > TypeScript/Python SDKs, and an MCP server across 17 prediction-market venues: integrate once, > then change the venue parameter to reach a different venue. This file is self-contained and written to be pasted into an AI agent. Everything needed to make a first successful call is below, in order. The full documentation corpus is at https://docs-production-631b.up.railway.app/llms-full.txt and the human docs at https://docs-production-631b.up.railway.app. Read the "Rules for agents" section at the end before you report results to a user. Predictefy's API is deliberately capability-honest: it answers "not supported" rather than returning invented data, and your summaries must preserve that distinction. ## Start here REST is the working integration path today. See "SDKs and MCP" below before you try to install a package. ### 1. Get an API key Keys are created at https://portal.predictefy.com/keys. Sign-up is free and needs no invite: every new account starts on the Free plan with 25,000 credits, refilled monthly. Trading ships on every plan, Free included; arbitrage, price-gap (discrepancy) queries, and bulk endpoints start at Builder, and every plan meters all usage in credits. The raw `pk_live_…` value is shown once; only its hash and display prefix are stored. Send the key only in the `Authorization` header. Never put it in a URL or query string. ### 2. Base URL and auth ``` Base URL: https://data.predictefy.com Header: Authorization: Bearer pk_live_YOUR_KEY ``` Your developer dashboard also shows this origin. Every route requires the key; anonymous requests answer `401 UNAUTHORIZED`. Only the health endpoints and the docs are open. ### 3. First call ```sh curl -s "https://data.predictefy.com/api/polymarket/fetchMarkets?limit=3&sort=volume" \ -H "Authorization: Bearer pk_live_YOUR_KEY" ``` Swap `polymarket` for any venue id, or use `router` to search every venue at once: ```sh curl -s "https://data.predictefy.com/api/router/fetchMarkets?query=election&status=active" \ -H "Authorization: Bearer pk_live_YOUR_KEY" ``` ### 4. Response envelope Success is always `{ success, data, meta, page }`: ```json { "success": true, "data": [ { "marketId": "…", "title": "…", "outcomes": [{ "outcomeId": "…", "label": "Yes", "price": 0.62 }], "volume24h": 123456.78, "liquidity": 98765.43, "url": "https://…", "asOf": "2026-07-03T09:15:00.000Z", "provenance": { "source": "venue-rest" }, "capabilities": { "read": true, "trade": false, "depth": true, "history": false } } ], "meta": { "asOf": "…", "provenance": { "source": "venue-rest" } }, "page": { "limit": 3, "offset": 0, "total": 1519, "hasMore": true, "nextCursor": "…" } } ``` Three honest-data fields ride on every record and you should surface them, not hide them: - `asOf` — when the data was snapshotted. Never present it as "now". - `provenance.source` — where it came from (`venue-rest`, `predictefy-live`, `fixture`). - `capabilities` — what this venue actually supports (`read` / `trade` / `depth` / `history`). `capabilities.trade` is `false` on every reads record by design; it describes the unused legacy unified `trade` verb, not whether execution exists. Execution is a separate service documented below. ## Verb family Every read route is `/api/{exchange}/{verb}`. The verb names are exchange-style. | Verb | Notes | | --- | --- | | `fetchMarkets`, `fetchMarket` | Catalog listing and single market. | | `fetchEvents`, `fetchEvent`, `fetchSeries` | Event- and series-shaped groupings. | | `fetchOrderBook`, `fetchOrderBooks` | Live book. Check the `synthetic` flag on the response. | | `fetchTrades` | Recent public tape snapshot, not a time-ranged query. | | `fetchOHLCV` | Historical candles. Venue-scoped; `router` is not supported. | | `getExecutionPrice`, `getExecutionPriceDetailed` | Stateless VWAP calculator over a book you pass in. It does not place, route, or prepare orders. | | `has` | Capability introspection — see below. | `router` is a pseudo-exchange that unions the list verbs, `fetchEvent`, and the stateless execution-price calculators across all venues. The complete endpoint contract is at https://docs-production-631b.up.railway.app/api/ — generated directly from the OpenAPI 3.1 spec, so it cannot drift from the API. The raw spec file is not published as a standalone download today; use the reference pages or the full corpus below. ## Capability introspection ```sh curl -s "https://data.predictefy.com/api/kalshi/has" \ -H "Authorization: Bearer pk_live_YOUR_KEY" ``` Call `has` before assuming a venue supports a verb. An unsupported venue/verb combination answers an honest `NOT_SUPPORTED` rather than empty or synthesized data — treat that as information, not as an error to retry or work around. ## Pagination List verbs accept `limit` (max 100), `offset`, `page`, and cursors. Prefer cursors: `nextCursor` freezes the catalog snapshot from page one, so a long walk never skips or double-counts rows that move while you page. ```sh # Page 2 — pass the previous response's nextCursor curl -s "https://data.predictefy.com/api/kalshi/fetchMarkets?limit=100&cursor=CURSOR_FROM_PAGE_1" \ -H "Authorization: Bearer pk_live_YOUR_KEY" ``` - Cursors expire after 60 seconds by default. Tune with `snapshotTTL` in milliseconds; `0` means the cursor chain never expires. The final page omits `nextCursor`. - **Drive your loop with `hasMore` / `nextCursor`, never with `total`.** `page.total` can be `null`: a count that overruns its budget is abandoned so your data page is still served. `null` means "not counted", never "zero matches", and `meta.totalUnavailable` says so. ## Errors Every error, 4xx or 5xx, uses one shape. `code`, `message`, and `retryable` are always present. ```json { "success": false, "error": { "code": "INSUFFICIENT_CREDITS", "message": "…", "retryable": false } } ``` | HTTP | code | Meaning | Retry? | | --- | --- | --- | --- | | 400 | `VALIDATION_ERROR` | Bad or missing parameters. | no | | 400 | `NOT_SUPPORTED` | Accepted-but-unsupported capability (honest gap). | no | | 401 | `UNAUTHORIZED` | Missing, unknown, or revoked API key. | no | | 402 | `INSUFFICIENT_CREDITS` | Balance below the endpoint weight. | after balance update | | 403 | `PLAN_REQUIRED` | Account does not include this route or history window. | after access update | | 404 | `EXCHANGE_NOT_AVAILABLE`, `MARKET_NOT_FOUND`, `EVENT_NOT_FOUND`, `OUTCOME_NOT_FOUND` | Unknown venue or record. | no | | 409 | `API_KEY_LIMIT` | Active API-key cap reached. | after revoking a key | | 429 | `RATE_LIMITED` | Request-rate window exceeded. | yes, back off | | 501 | `NOT_SUPPORTED` | Venue has no public feed for this verb. | no | | 503 | `CATALOG_UNAVAILABLE`, `PLATFORM_UNAVAILABLE`, `HISTORY_UNAVAILABLE`, `BILLING_UNAVAILABLE` | Temporary outage, fail-closed. | yes, backoff | ## Venues 17 venue ids, usable as the `{exchange}` path segment: `polymarket` · `kalshi` · `smarkets` · `opinion` · `hyperliquid` · `limitless` · `polymarket_us` · `sxbet` · `myriad` · `gemini` · `rain` · `predictfun` · `pascal` · `xo` · `pred` · `predictstreet` · `novig` — plus `router`. - **Real CLOB depth:** polymarket, kalshi, smarkets (delayed quotes), opinion, hyperliquid, limitless (CLOB markets only), polymarket_us (~30s CDN cache), sxbet, predictfun, pascal, xo, pred, predictstreet, novig. - **Emulated books** (reconstructed top-of-book, indicative not executable, `synthetic: true`): myriad, gemini, rain. - **Public trades tape:** polymarket, kalshi, hyperliquid, limitless, sxbet, myriad, gemini, predictfun, pascal. Every other venue answers `501 NOT_SUPPORTED` rather than synthesizing trades. - **New-venue boundary:** `pascal`, `xo`, and `pred` serve catalog reads and real order books (plus a trades tape on Pascal only). All three have source-ready, default-off isolated execution lanes. PredictStreet serves keyless catalog/detail reads and real two-sided books, plus its own gated, default-off VAULT execution lane. None has a hosted account or venue-history lane. Venue-side access limits and owner/compliance gates still apply. - **sxbet caveat:** it has a real CLOB, but hosted `fetchOrderBook` can currently return an empty book. Its tape, OHLCV, and capture capabilities are independent of that. - An **empty real book** is a valid "no liquidity right now" state. Check the levels, not just flags. Full matrix: https://docs-production-631b.up.railway.app/reference/venues/ ## Historical data `GET /api/{exchange}/fetchOHLCV?outcomeId=…&resolution=1h&limit=500` - `resolution`: `1s`/`5s`/`10s`/`30s` are trade-derived on a small venue set; `1m`/`1h`/`1d` are stored; `5m`/`15m`/`30m`/`4h`/`6h` are query-time rollups (`sourceType: rollup`). - `limit` caps at 5,000 candles per call. Page longer ranges with `start`/`end`. - Stored for the 13 venues with a history lane. Pascal, XO, PRED, PredictStreet, and Novig answer honestly instead of serving empty candles. `router` is not supported — candles are venue-scoped. Every candle carries `source`, `sourceType`, `quality` (`ok`/`partial`/`suspect`/`mixed`) and `isTrueCandle`, so you can tell a true venue candle from a derived one. `volume` is `null` where the source does not provide it. Capture and backfill are availability-dependent and no uninterrupted-capture or freshness guarantee is made. Empty data means the range predates capture, holds no trades, or crosses a gap — request the exact range you need rather than assuming depth. ## Cross-venue - `GET /v1/clusters`, `GET /v1/clusters/:id` — equivalent markets matched across venues. Members carry a `similarity` score: raw embedding similarity, deliberately **not** a calibrated probability that the markets are equivalent. Cluster ids are stable. - `GET /v1/discrepancies` — mid-price gaps between cluster members. Add `?live=true` to recompute from live order-book mids; `meta.live` tells you which you got. - `GET /api/router/fetchArbitrage?contracts=100` — router-only. It grades a bounded contract size against live asks. A row earns the executable label only when every gate passes: live non-synthetic asks on both legs, open market status, full depth at the requested size, a VERIFIED per-venue fee model, the resolution-equivalence gate, and positive net edge after all costs. Everything else stays labeled an **indicative price discrepancy** with machine-readable reasons such as `synthetic_book`, `insufficient_depth`, `unverified_fees`, or `market_not_open`. Add `executableOnly=true` for passing rows only. A price gap is only tradeable if executable asks, depth, fees and gas, open status, and resolution equivalence all hold live at execution time. The discrepancy endpoints do not apply those gates. They tell you where to look, not what to trade. ## Streaming WebSocket at `/v1/stream` on the streaming origin shown in your dashboard. Auth with the same `pk_live_…` key: an `Authorization: Bearer` header, or a first-frame `{ "op": "auth", "apiKey": … }` within 10 seconds for browser clients. Keys in the URL are deliberately unsupported. ```jsonc { "op": "subscribe", "channel": "orderbook", "venue": "polymarket", "marketId": "" } { "op": "subscribe", "channel": "trades", "venue": "", "marketId": "" } { "op": "subscribeFeedTicker", "feed": "binance", "symbol": "BTC/USDT" } ``` - `marketId` is the **venue-native** book id, not always the unified `marketId`. For polymarket it is the CLOB asset id, which the API returns as the outcome's `outcomeId` — the same value you pass to `fetchOrderBook`. A wrong id acks `subscribed` and then delivers zero frames, which looks identical to a quiet market. - `snapshot` and `update` both carry the **full book**, never deltas. - Protocol problems (`BAD_MESSAGE`, `NOT_SUPPORTED`, `NOT_SUBSCRIBED`, `SUBSCRIPTION_LIMIT`) are non-fatal and leave the socket open. Close codes: `4001` unauthorized, `4002` insufficient credits, `4003` platform unavailable, `4004` connection limit, `4008` rate limited. - Chainlink feed streaming is poll-backed, not a push stream, and every frame discloses `sourceMetadata.transport = "poll"`. ## Execution Execution is a **separate, isolated, non-custodial service** — not the reads API, which never proxies it. The execution origin is an explicit opt-in (`PREDICTEFY_EXEC_BASE_URL` in the SDK, or copy it from the dashboard) and has no implicit default. The service builds an unsigned, venue-shaped artifact; **your** signer signs it in your own process; the service revalidates owner binding, artifact bounds, and spend caps, then relays it. Predictefy holds no user signing keys and **there is no generic server-side signing route** — do not look for one. - Routes: `POST /v1/exec/:venue/orders/build`, `.../orders/submit`, `.../orders/:executionId/cancel`, `.../orders/:executionId/modify`, `.../orders/:executionId/refresh`, `GET /v1/exec/:venue/orders`, `.../trades`, `.../positions`. - Every build, submit, cancel, and modify POST requires an `Idempotency-Key` header; a missing one is `400 IDEMPOTENCY_KEY_REQUIRED`. Replaying a key returns the stored execution with `Idempotency-Replay: true`. `refresh` is the read-only exception. - **`GET /v1/exec/venues` is the authoritative live list.** Do not infer execution support from data coverage. A venue listed without `build` genuinely cannot build. - Build is not metered; credits are charged on submit, cancel, and modify. - Spend caps default to **100 USD per order** and **1,000 USD per API key per rolling 24 hours**. A violation is rejected; the service never silently reduces an order. - Order body shape is venue-specific by design — the venues do not agree on one order struct and Predictefy does not invent one. No venue accepts a price in cents. - Every key carries the `trade` scope by default; a key without it gets `403 SCOPE_MISSING`. - Hosted `fetchBalance` intentionally returns `501 NOT_SUPPORTED`. - SX Bet has no hosted execution. Its client-side SDK integration keeps keys in your process and requires a registered sx.bet account plus one-time betting enablement. Trading can lose money. Validate every unsigned artifact before signing, and never present an indicative price discrepancy as evidence that a trade is executable or profitable. ## Accounts `GET /v1/accounts/{venue}/capabilities`, then `/{accountId}`, `/balances`, `/positions`, `/open-orders`, `/fills`. Each resource has its own envelope reporting `available`, `owner_auth_required`, `not_supported`, or `temporarily_unavailable` — one upstream failure never makes another resource look successful. Call `capabilities` before requesting a dedicated list. Owner-authenticated resources (Kalshi RSA, Smarkets session, Polymarket CLOB L2, Opinion caller key) route locally through the SDK and never transit the hosted API. ## Funding Execution assumes the venue is already funded. Predictefy holds no funds and no keys: every funding route returns provider-native data or an unsigned artifact, and the caller signs. - `GET /v1/funding/{venue}/requirements` — what that venue needs before it can trade. - `POST /v1/funding/{venue}/steps` — unsigned transactions (Polymarket wrap/approve; Hyperliquid reports readiness only and returns no transfer step). - `GET /v1/bridge/quote` — a routed quote. The destination is **either** `toVenue` **or** an explicit `toChain` + `toToken` pair, never both. The explicit form is not restricted to Predictefy venues: any LI.FI-supported chain and token works, including a chain's native gas token via the zero-address sentinel `0x0000000000000000000000000000000000000000`. Cross-VM destinations such as Solana additionally require `toAddress` — without it LI.FI defaults the recipient to the EVM `fromAddress` and rejects the quote. - `POST /v1/bridge/session` — the Glide-backed venues, Hyperliquid and SX Bet. Gas is a two-chain problem: the approval and order that follow a bridge need native gas on both the source and destination chains. Quote native gas to the destination chain first, then bridge the collateral. **There is no withdrawal and no bridge-out route.** Each venue is a custody island: funds leave only by that venue's own rails, and no balance moves between venues through Predictefy. This is the no-escrow posture rather than a gap, and unified funding is roadmap — never tell a user Predictefy can withdraw or transfer their funds. Hyperliquid's withdrawal reaches **Arbitrum only**, because its `withdraw3` action is the venue's Arbitrum bridge; the SDK's `buildWithdrawRequest` is build-only and the caller posts it to the venue. Any other chain is two legs — withdraw to Arbitrum, then bridge onward with `GET /v1/bridge/quote`. ## Credits Metered per action: 1 credit for metadata/search/price snapshot, 2 for trades or candles, 5 for an order-book snapshot, history query, cross-match lookup, or order submit/cancel, 10 for a cross-venue comparison, price-gap query, or smart-money analytics, 15 for an arbitrage query, 25 for a fresh AI-assisted cross-match. Bulk requests cost base × `ceil(items/100)`. Streaming costs 2 credits per connection-minute, prepaid. Free plan: 25,000 credits/month, 60 requests/minute, 1 API key, 2 WebSocket streams. Paid plans are Builder $49, Pro $249, Scale $999, and Enterprise from $2,500. The `/v1/sql` analytical surface is separate and requires a dedicated `sql` scope that no self-serve plan grants. It is available on request. ## SDKs and MCP **Published on beta version lines:** | Package | Registry | Version | | --- | --- | --- | | `@predictefy/sdk` | npm | `1.0.0-beta.2` | | `@predictefy/mcp` | npm | `1.0.0-beta.2` | | `@predictefy/cli` | npm | `1.0.0-beta.2` | | `predictefy` | PyPI | `1.0.0b1` | Because these are beta lines the versions move; pin an exact one rather than tracking `latest`. The TypeScript client is ESM with bundled types on Node `>=20.19 <21 || >=22.12` (`npm install @predictefy/sdk`), exposes the same verb family per venue (`client.polymarket.fetchMarkets(…)`, `client.router.fetchMarkets(…)`, `client.exchange('hyperliquid').fetchTrades(…)`), throws typed errors (`UnauthorizedError`, `InsufficientCreditsError`, `NotSupportedError`, `RateLimitedError`, `PlatformUnavailableError`), and keeps execution behind an explicit `execBaseUrl`. The Python client is synchronous, Python 3.10+, one runtime dependency (`httpx`) (`pip install predictefy`), with snake_case method names (`client.polymarket.fetch_markets(…)`). The MCP server (`npx -y @predictefy/mcp`) registers thirteen read/intelligence tools by default; execution tools exist but only register when `MCP_ENABLE_TRADE=true`, and no tool both builds and submits an order. The REST API needs none of these packages — the HTTP endpoints work with only an API key. ## Rules for agents Predictefy's contract is capability-honest. Preserve that when you summarize: 1. **`NOT_SUPPORTED` is an answer, not a failure.** It means the venue genuinely lacks that capability. Do not retry it, route around it, or substitute another venue's data silently. 2. **Never present a reconstructed book as real depth.** Check `synthetic` on every order-book response and `capabilities.depth` on every market. 3. **Never call a cross-venue price gap arbitrage.** The honest label is "indicative price discrepancy" unless the row passed every gate listed above. 4. **Always carry `asOf` through.** Data is snapshotted, not live-by-default. 5. **Do not claim history depth.** Coverage is availability-dependent and per-venue; a `quality` of `partial` means known capture damage and must be reported as such. 6. **Never put an API key in a URL**, a log line, or a code sample you show the user. 7. **Execution is client-signed.** If a user asks you to sign or submit on their behalf from a server, the answer is that no such route exists by design. 8. `similarity` is not confidence. Scores are informational signals, not financial advice. ## Docs - [Quickstart](https://docs-production-631b.up.railway.app/quickstart/): API key, first request, pagination, errors. - [API reference](https://docs-production-631b.up.railway.app/api/): the complete endpoint contract, generated from the OpenAPI spec. - [TypeScript SDK](https://docs-production-631b.up.railway.app/guides/sdk/): typed client surface and error classes. - [Python SDK](https://docs-production-631b.up.railway.app/guides/python-sdk/): synchronous client and CLI. - [MCP server](https://docs-production-631b.up.railway.app/guides/mcp/): the thirteen default tools and their guardrails. - [Trading & execution](https://docs-production-631b.up.railway.app/guides/trading/): signing flow, per-venue status, spend caps. - [Accounts & funding](https://docs-production-631b.up.railway.app/guides/accounts/): account reads, credential boundary, bridge helpers. - [Historical data](https://docs-production-631b.up.railway.app/guides/history/): OHLCV parameters, candle provenance, coverage depth. - [Cross-venue data](https://docs-production-631b.up.railway.app/guides/cross-venue/): clusters, discrepancies, executable gates. - [Streaming](https://docs-production-631b.up.railway.app/guides/streaming/): WebSocket protocol, auth handshake, close codes. - [TradingView charts](https://docs-production-631b.up.railway.app/guides/tradingview-charts/): datafeed adapter for TradingView. - [Venue coverage](https://docs-production-631b.up.railway.app/reference/venues/): the per-venue capability matrix. - [Trader Intelligence](https://docs-production-631b.up.railway.app/reference/trader-intelligence/): wallet-attributed tapes, leaderboards, smart money. - [Pricing, credits & billing](https://docs-production-631b.up.railway.app/guides/credits/): plans, action costs, overage. ## Optional - [Full documentation corpus](https://docs-production-631b.up.railway.app/llms-full.txt): every page above, concatenated, plus a table of every API operation. - [Developer dashboard](https://portal.predictefy.com/keys): create keys, view usage and the credit ledger.