Sports odds in one schema, with the +EV worked out.
UnerringAPI reads sportsbooks, exchanges and pick'em apps, merges them into one event per game, and scores each price against a sharp consensus. Arbitrage, middles and low holds come from the same board. Read it over REST, or hold a WebSocket stream open.
One schema
Each venue answers in the same shape: event, bookmaker, market, outcome. What only some venues have is an extra field on that shape, not a different format.
| Field | Sportsbook | Exchange or prediction market | Pick'em app |
|---|---|---|---|
price | American, decimal or probability | American, decimal or probability | Null unless the app publishes one |
liquidity | Not sent | Dollars at this price, where known | Not sent |
multiplier | Not sent | Not sent | Per-pick payout, where published |
variant | Not sent | Not sent | standard, goblin or demon |
time_basis | On the bookmaker, not each outcome: snapshot when the book's newest copy is older than our receipt (its Date, Age or the venue's own read time say so), read when it is as of our receipt | ||
{
"id": "mkt_0k2v9qa1x7m3pc",
"key": "total",
"period": "full_game",
"line": 224.5,
"outcomes": [
{ "id": "sel_1f8s2ld0q9w4ze", "name": "Over", "side": "over",
"point": 224.5, "price": -108 },
{ "id": "sel_0p3n7ty5h2c6vb", "name": "Under", "side": "under",
"point": 224.5, "price": -112 }
],
"suspended": false
}
Example of a market's shape. The values are illustrative, not live prices.
Computed for you
The same board of current prices feeds all of these, after stale, suspended and already-started prices are dropped. A book never helps set its own fair price.
-
+EV
/v1/evEach price against a weighted consensus of the other price families, with the margin removed. Rows carry the fair probability, EV percent, Kelly fraction and the books that set the price.
-
Arbitrage
/v1/arbitrageTwo-way pairs across different price families, with the stake split for each leg. A wide gap between the times the legs were read is flagged.
-
Middles
/v1/middlesOver the lower total and under the higher, or two spreads that leave a gap. Each row gives the window and what it costs to hold both legs.
-
Low holds
/v1/holdsThe lowest combined margin on each two-way market, taking the best price on each side.
-
Exchange depth
/v1/smart-moneyAn exchange price with known depth, beside the best sportsbook price on the other side. It reports depth, not trade flow.
-
Pick'em edges
/v1/dfsA fair chance for each pick'em line from the sharp books' prices, against what that pick must hit to break even on that app.
REST and a stream
REST answers are JSON with a request id, the credits used and paging details. Rows that don't fit on a page are reported, so a short answer is never mistaken for a complete one.
The stream sends a snapshot, then a delta when a read changes something. Its rate follows how often each venue is read, not a fixed tick. A sequence number shows you any gap.
curl -s "https://unerring-api.liam-banks2004.workers.dev/v1/ev?league=nba&min_ev=2" \
-H "Authorization: Bearer $UNERRING_KEY"
const ws = new WebSocket("wss://unerring-api.liam-banks2004.workers.dev/v1/stream");
ws.onopen = () => ws.send(JSON.stringify({ type: "auth", api_key: key }));
ws.onmessage = ({ data }) => {
const message = JSON.parse(data);
if (message.type === "welcome") {
ws.send(JSON.stringify({ type: "subscribe", leagues: ["nba"], markets: ["main"] }));
}
// snapshot, delta, event, heartbeat, pong, error
};
Coverage is measured
A book's name in our list says nothing about whether we have its prices. Each book has a state worked out from prices actually seen, and a reason where it isn't feeding.
- Feeding
- Its prices were seen recently and it is on the current board.
- Stale
- Its prices have been seen, but not recently, or it is no longer on the board.
- No data
- We expect prices from it and have never seen any.
- Not expected
- No online prices to collect: a retail venue, a closed app, a salary-cap contest or something that isn't a book.
Plans
A request costs 0 to 3 credits, whatever the size of the answer. Errors cost nothing. A stream costs 1 credit to connect and 1 for each minute it stays open.
| Plan | Per 30 days | Credits | Requests a minute | Stream sockets | Includes |
|---|---|---|---|---|---|
| Sandbox | $0 | 50, one time | 20 | 0 | Pre-game odds, props, history |
| Edge | $49.99 | 150,000 | 300 | 0 | Sandbox, plus +EV, arbitrage, middles, holds, exchange depth, pick'em, futures |
| Sharp | $199.99 | Unlimited | 1,200 | 0 | Same as Edge |
| Syndicate | $249.99 | Unlimited | 3,000 | 10 | Edge, plus live events and the stream |
| Enterprise | Not listed | Unlimited | 6,000 | 50 | Same as Syndicate |
Paid checkout gives 30 days of access per payment and does not renew automatically. An API key and account are required first; the operator currently issues both. The futures endpoint currently returns an empty list.
Plans are priced in USD. Operated by VyrexCode (Vyrex Software & Development). Review our Terms and Privacy Policy. For billing or refund enquiries, contact support.