Predictapp logo

predictapp API reference

Nine endpoints, JSON in and JSON out. Find a game, quote it, read it with a spending ceiling, and keep the receipt.

Base address and authentication

  • ›Every request goes to https://app.predictapp.io/api/v1. Send your API key as a bearer token in the Authorization header.
  • ›Create keys in the web app, under Settings, API & MCP. A key is shown once, when you create it. You can have several; they all share one wallet and the same included calls.
  • ›Keep keys on your server or in your API client's secret storage. Never put one in browser JavaScript, a screenshot, analytics or a commit. If a key may have leaked, revoke it in Settings.
  • ›Keys, top-ups and the API & MCP subscription are managed only in the web app. The API cannot create keys or move money.
shell
export PREDICTAPP_ORIGIN=https://app.predictapp.io
export PREDICTAPP_API_KEY=<your-api-key>

Conventions

  • ›POST bodies are JSON objects sent with Content-Type: application/json. Every field goes in the body: the API rejects query parameters.
  • ›Unknown fields are rejected. Send only the fields documented here and in the machine contract.
  • ›Amounts are integer euro cents: 25 means €0.25.
  • ›Probabilities are fractions from 0 to 1, unless the field name ends in _pct.
  • ›IDs are decimal strings, not numbers: "123", not 123. Take them from discovery.
  • ›A game that discovery returns as event_id is sent as game_id to /props.
  • ›Request bodies are limited to 32 KiB.
  • ›Predictions are pregame forecasts. freshness.prediction_generated_at says when the model produced them. They are not live scores or bookmaker odds.

Included calls, prepaid and the spending ceiling

Included calls are the default: leave access_mode out, or send "subscription". Paid plans include a monthly number of calls: Soccer 500 (Soccer only), NFL 500 (NFL only), Global 650 (both), and the API & MCP subscription 1,000 (both). Plans you hold add up, and each keeps the sports it covers. Calls reset each month on your subscription anniversary, on yearly plans too. A call like this spends no credit and buys nothing to keep. Each successful one uses one included call. If nothing you hold covers it, or your calls are used up, the call fails; it never falls back to your wallet.

Prepaid is what you ask for: send access_mode: "prepaid" on the call. It buys what you ask for from your wallet, and you own it: reading it again costs nothing. Buying part of a game counts toward the whole game's price, and owning the whole game covers its parts. The free credit on a new account needs this mode too.

max_charge_cents is the most a call may spend, not what it spends. If the real price is 10 and your ceiling is 50, you pay 10. A ceiling of 0 reads what you already own and refuses anything new. It is required on every prediction request, included calls too, where 0 is right. Saves default it to 1. Quotes do not take it.

Not sure what a call will cost? Ask /quote first with access_mode: "prepaid". It is free and answers for your account, counting what you already own.

Your balance and included calls

GET /api/v1/accountAPI key

Your wallet balance and the calls you have left. Free.

  • ›balance_cents is your wallet, in cents.
  • ›subscription reports active, state, used, reserved, remaining and cancel_at_period_end across everything you hold. Reserved calls are in flight and count against remaining until they finish.
  • ›subscription.allowances lists each plan separately: source, plan, products, period_start, period_end, used, reserved, remaining and requests_per_period. When you hold more than one, read the dates there: the top-level period is empty.
Your balance and included calls
curl "$PREDICTAPP_ORIGIN/api/v1/account"   -H "Authorization: Bearer $PREDICTAPP_API_KEY"

Find games and players

POST /api/v1/discoverNo key needed

Find upcoming games and players, and their IDs. Free, and works without a key; a key you do send is checked.

  • ›sport is soccer or nfl. product is game, props or fantasy; Soccer supports game only.
  • ›query is a team or player name. Optional: date (a UTC day, YYYY-MM-DD), season_year and week (NFL regular season, 1 to 18), and limit (up to 20).
  • ›It returns identities and kickoff times, not predictions. An empty list means nothing upcoming matched.
  • ›There is no separate team or player list: discovery is how you get IDs. Use fresh results; IDs from old examples will not work.
Find a Soccer game
curl "$PREDICTAPP_ORIGIN/api/v1/discover" \
  -H "Content-Type: application/json" \
  -d '{"sport":"soccer","product":"game","query":"Arsenal","limit":5}'
Find an NFL game for props
curl "$PREDICTAPP_ORIGIN/api/v1/discover" \
  -H "Content-Type: application/json" \
  -d '{"sport":"nfl","product":"props","query":"Kansas City","limit":5}'

Price a call before you make it

POST /api/v1/quoteAPI key

What a call would charge your account. Free: it buys nothing and returns no prediction.

  • ›operation is game, props, joint or fantasy, followed by the same selector the real call uses.
  • ›charged_cents in the answer is the proposed charge, not money taken. What you own quotes at 0.
  • ›A quote is advice, not a reserved price.
Quote a full Soccer game on prepaid
curl "$PREDICTAPP_ORIGIN/api/v1/quote" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation":"game","sport":"soccer","event_id":"<event_id>","scope":{"kind":"full"},"access_mode":"prepaid"}'

A Soccer or NFL game

POST /api/v1/gameAPI key

Probabilities, projections and fair prices for one game.

  • ›scope is {"kind":"full"} for the whole game, or {"kind":"family","family":...}. Soccer families: outcomes, goals, match_flow, corners. NFL families: outcomes, scoring, team_production.
  • ›NFL team_production is per team: add "team": "home" or "away". It returns that team's expected points and production, not both teams.
  • ›NFL only: line_query asks for one exact line, total_points (side over or under), spread (team home or away) or team_total_points, in half-point steps and within the family you chose.
  • ›Settlements give win, push and loss probabilities. Where a fair price is returned, use it rather than 1 divided by the win probability, which ignores pushes.
  • ›New purchases close at kickoff. A game you already own can still be read afterwards.
Read a full Soccer game on your included calls
curl "$PREDICTAPP_ORIGIN/api/v1/game" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sport":"soccer","event_id":"<event_id>","scope":{"kind":"full"},"max_charge_cents":0}'
Buy a full Soccer game with credit (ceiling €0.25)
curl "$PREDICTAPP_ORIGIN/api/v1/game" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sport":"soccer","event_id":"<event_id>","scope":{"kind":"full"},"access_mode":"prepaid","max_charge_cents":25}'
Buy NFL home team production with credit (ceiling €0.10)
curl "$PREDICTAPP_ORIGIN/api/v1/game" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sport":"nfl","event_id":"<event_id>","scope":{"kind":"family","family":"team_production","team":"home"},"access_mode":"prepaid","max_charge_cents":10}'

NFL player props

POST /api/v1/propsAPI key

Passing, rushing, receiving and touchdowns.

  • ›game_id is the event_id discovery returned for the game.
  • ›scope is {"kind":"player_family","family":...,"player_id":...} for one player and family (€0.10), {"kind":"family","family":...} for one family across the game (€0.75), or {"kind":"all"} for every family (€3.00).
  • ›line_query must match the player and family you chose. Lines move in half-point steps.
  • ›Interceptions are not a props family. They appear in Fantasy stat lines.
Buy one player's passing props with credit (ceiling €0.10)
curl "$PREDICTAPP_ORIGIN/api/v1/props" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"game_id":"<event_id>","scope":{"kind":"player_family","family":"passing","player_id":"<player_id>"},"access_mode":"prepaid","max_charge_cents":10}'

Two events in the same game

POST /api/v1/jointAPI key

The chance that two events in one game both happen, from the model's joint distribution.

  • ›event_a and event_b are two different supported events from the same game.
  • ›A new pair costs €0.20, or €0.02 if you already own the full game. A pair you own, in either order, is free to read again.
  • ›Pair charges sit outside game caps and do not unlock the game's families.
Buy home win and over 40.5 points with credit (ceiling €0.20)
curl "$PREDICTAPP_ORIGIN/api/v1/joint" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sport":"nfl","event_id":"<event_id>","event_a":{"market":"game_winner","outcome":"home"},"event_b":{"market":"total_points","side":"over","line":40.5},"access_mode":"prepaid","max_charge_cents":20}'

NFL Fantasy

POST /api/v1/fantasyAPI key

One week of Fantasy: rankings, a player's projection, a threshold, or Start/Sit.

  • ›operation is rankings (optional position, team, and limit up to 100), player (player_id), threshold (player_id, side, threshold) or compare (player_ids, start_count).
  • ›format is standard, half_ppr or ppr.
  • ›compare takes 2 to 4 different players and a start_count smaller than the number of players. Each player row has start (true or false) and start_pct. outscore_pct compares players with each other; it is not a game result.
  • ›With access_mode: "prepaid", the first call buys the week for €5.00, covering the games still to be played at that moment; send max_charge_cents: 500. Later prepaid calls in that week can send 0.
  • ›There is no lineup optimizer and no Sleeper connection.
QB rankings on your included calls
curl "$PREDICTAPP_ORIGIN/api/v1/fantasy" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation":"rankings","season_year":2026,"week":6,"format":"ppr","position":"QB","limit":10,"access_mode":"subscription","max_charge_cents":0}'
Start/Sit within a week you own
curl "$PREDICTAPP_ORIGIN/api/v1/fantasy" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation":"compare","season_year":2026,"week":6,"format":"ppr","player_ids":["<player_a_id>","<player_b_id>"],"start_count":1,"access_mode":"prepaid","max_charge_cents":0}'

Save a bet

POST /api/v1/forecast/saveAPI key

Save a bet you actually placed. predictapp records the model's probability and fair price at that moment and grades the bet automatically.

  • ›It costs €0.01 from your wallet, on every plan. You need to own the game's prediction, or hold a paid plan that covers its sport.
  • ›selections is one supported single, or a supported two-event same-game pair. Props, Fantasy and multi-game parlays cannot be saved.
  • ›decimal_price is the price you took. Leave it out and the fair price is used, marked price_source: "fair".
  • ›Safe retries: generate a UUID as request_id before the first attempt and reuse it with the same details. A retry returns the original save and charges nothing. The same ID with different details returns IDEMPOTENCY_CONFLICT. Without a request_id, repeating a call can save, and charge for, a second bet.
Save a home-win bet at 2.20
curl "$PREDICTAPP_ORIGIN/api/v1/forecast/save" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"sport":"nfl","event_id":"<event_id>","selections":[{"market":"game_winner","outcome":"home"}],"units":1,"decimal_price":2.2,"max_charge_cents":1}'

Read your saved bets

POST /api/v1/forecast/readAPI key

The bets you saved through the API or MCP. Free.

  • ›Send either {"ids": [...]}, up to 50, or {"limit": 20, "cursor": ...}. Not both.
  • ›Newest first. next_cursor: null means there are no more.
  • ›Only bets saved through the API or MCP are listed, not bets saved in the app.
List your saved bets
curl "$PREDICTAPP_ORIGIN/api/v1/forecast/read" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"limit":20}'
Read saved bets by ID
curl "$PREDICTAPP_ORIGIN/api/v1/forecast/read" \
  -H "Authorization: Bearer $PREDICTAPP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids":["<saved_bet_uuid>"]}'

The receipt

Every prediction answer has three parts: data, freshness and billing. The shape of data depends on the endpoint. billing is your receipt:

  • resource_key: what you read
  • owned: whether you own it now
  • charged_cents: what this call took from your wallet
  • balance_cents: your wallet after the call
  • inherited_from: the larger purchase that covered this read, if any
  • coverage: Fantasy only: full or remaining, the games the week covers
  • access_mode: prepaid or subscription, with your calls left on included calls

An included call normally shows owned: false and charged_cents: 0. That is expected: the call used one of your included calls instead of credit.

Errors

An error is {"error": "CODE"} with an HTTP status. There is no message field: act on the code.

CodeHTTPWhat it means
BAD_REQUEST400The JSON, a field or an ID is invalid, or a field is unknown. Also comes with 405, 413 or 415 for the wrong method, a body over 32 KiB or a missing JSON content type.
UNSUPPORTED_SCOPE400That sport, product, market or selection is not supported in this combination.
UNAUTHENTICATED401The key is missing, invalid or revoked.
INSUFFICIENT_CREDIT402Your wallet cannot cover the charge. Top up in the web app.
SUBSCRIPTION_REQUIRED402This account has no paid plan with included calls. Get one, or send access_mode: "prepaid".
FORBIDDEN403This key or connection is not allowed to do that.
PREDICTION_NOT_OWNED403Saving a bet needs the game's prediction owned, or a paid plan that covers its sport.
PRODUCT_NOT_INCLUDED403Your plans do not cover this: a Soccer plan asking for an NFL game, for example. Add a plan that does, or send access_mode: "prepaid".
NOT_COVERED404That prediction is not available, for example the game is not covered or sales have closed. It does not mean you have not paid.
MAX_CHARGE_EXCEEDED409The real price is above your max_charge_cents, so the call was refused.
IDEMPOTENCY_CONFLICT409This request_id was used before with different bet details.
RATE_LIMITED429Too many operations. Slow down and try again.
SUBSCRIPTION_QUOTA_EXHAUSTED429Your included calls are used up, or too many are in flight. Check GET /account.
TEMPORARILY_UNAVAILABLE503A temporary problem on our side. Try again shortly.
NOT_FOUND404Web app settings only: the key you tried to revoke does not exist. API-key requests do not return it.
KEY_LIMIT_REACHED409Web app settings only: you already have the maximum number of keys. API-key requests do not return it.
SUBSCRIPTION_ACTIVE409Web app settings only: you already have an active subscription. API-key requests do not return it.

Failures at the network or hosting layer may not use this format, and the API does not promise a Retry-After header.

Limits

  • ›60 operations per minute per account, shared by all your keys and connections. Free calls count too.
  • ›Each prediction allows a bounded set of exact-line queries: 32 distinct ones per domain.
  • ›Discovery returns at most 20 results. Fantasy rankings return at most 100 players.
  • ›Request bodies are limited to 32 KiB.

Machine contract

The exact schema of every request and response, with the prices, errors and limits, is published as a machine contract. It is a custom document of JSON Schemas (draft 2020-12), not an OpenAPI file. Where this page and the contract disagree, the contract is right.

https://app.predictapp.io/machine-contract.json