OPAP Odds API (Allwyn / OPAP Store)
The ArbPlay OPAP odds API serves the Allwyn store offer's own JSON over HTTPS in six files: live and pre-match for soccer, basketball and tennis. Every event carries a Betradar id, and pre-match soccer reaches about 2 weeks ahead. Live odds refresh about every 1–3 seconds, pre-match about every 4–7.
OPAP, part of the Allwyn group, is Greece's national betting operator. The data is the Allwyn store offer (formerly OPAP Store): the odds you bet on in an Allwyn shop, with each pre-match event's store code. OPAP's separate online sportsbook is not part of this API. The marketplace listings are named Allwyn Odds and OPAP Store Odds API.
Key facts
| Bookmaker | OPAP (Allwyn group), Greece |
|---|---|
| Company key | opapstore (listings: "Allwyn Odds", "OPAP Store Odds API") |
| Files | 6: site_{live,pregame}_opapstore_{soccer,basketball,tennis}.json |
| Pre-match coverage | Soccer about 2 weeks ahead; basketball about 1 week; tennis 1–2 days |
| Refresh | Live about every 1–3 s, pre-match about every 4–7 s |
| Odds format | Decimal (prices[].decimal) plus fractional (numerator/denominator) |
| Cross-bookmaker id | Betradar: externalIds[] with provider: "betradar" (sr:match:<id>) — on every event |
| Schema | data.events[].markets[].outcomes[].prices[] |
| Market groups | MATCH_RESULT, TOTAL_GOALS_OVER/UNDER, DOUBLE_CHANCE, BOTH_TEAMS_TO_SCORE, NO_BET_DRAW, ASIAN_HANDICAP, CORNERS_OVER/UNDER… |
| Access | RapidAPI, Zyla API Hub or JoJ API listing, or a direct X-API-Key from ArbPlay |
Files and what's inside
Every file is OPAP's own JSON, served unchanged inside the API envelope. Refresh: live files about every 1–3 s, pre-match files about every 4–7 s.
| File | What's inside | Refresh |
|---|---|---|
site_live_opapstore_soccer.json | Live soccer with match result, totals, BTTS, corners and draw no bet | ≈1–3 s |
site_live_opapstore_basketball.json | Live basketball | ≈1–3 s |
site_live_opapstore_tennis.json | Live tennis | ≈1–3 s |
site_pregame_opapstore_soccer.json | Pre-match soccer — match result, totals, double chance, BTTS, half-time, Asian handicap, corners | ≈4–7 s |
site_pregame_opapstore_basketball.json | Pre-match basketball | ≈4–7 s |
site_pregame_opapstore_tennis.json | Pre-match tennis | ≈4–7 s |
Pre-match markets by sport
| Sport | Markets |
|---|---|
| Soccer | Match result, half-time result, total goals lines, double chance, both teams to score, draw no bet, Asian handicap, corners |
| Basketball | Money line, point spread lines, total points lines |
| Tennis | Match winner, set winner, game handicap |
Every bookmaker compared: sports and markets per bookmaker.
Field map: where each value lives
Paths start at data.data.events[] (the file has its own data key).
| Value | Path |
|---|---|
| Event id | events[].id |
| Name | events[].name ("Home v Away") |
| Teams | events[].teams[].name with side HOME / AWAY |
| League | events[].type.name |
| Country / region | events[].class.name |
| Sport | events[].category.name |
| Start time | events[].startTime (ISO) |
| In play | events[].liveNow |
| Market | markets[].name (line included, e.g. "Total Goals Over / Under 2.5"), .groupCode |
| Selection, price | markets[].outcomes[].name, .subType (H/D/A in match result) → prices[0].decimal |
| Betradar id | events[].externalIds[] where provider == "betradar" → id |
| Status | status ACTIVE / SUSPENDED and active on events, markets and outcomes |
| Store code (pre-match) | events[].retailCode: the code a shop uses to find the event; not on every event |
Real sample
An abridged record from site_pregame_opapstore_soccer.json: real values, most fields left out so the structure is readable. The downloads below keep every field.
{
"data": {
"events": [
{
"id": "12562240",
"name": "Wydad Casablanca v Wydad Temara",
"startTime": "2026-09-26T20:00:00Z",
"liveNow": false,
"category": {
"name": "Football"
},
"class": {
"name": "Morocco"
},
"type": {
"name": "Botola"
},
"teams": [
{
"id": null,
"name": "Wydad Casablanca",
"side": "HOME"
},
{
"id": null,
"name": "Wydad Temara",
"side": "AWAY"
}
],
"externalIds": [
{
"id": "sr:match:74829634",
"provider": "betradar"
}
],
"markets": [
{
"name": "Match Result",
"groupCode": "MATCH_RESULT",
"outcomes": [
{
"name": "Wydad Temara",
"subType": "A",
"prices": [
{
"decimal": 6.0,
"numerator": 5,
"denominator": 1
}
]
},
{
"name": "Wydad Casablanca",
"subType": "H",
"prices": [
{
"decimal": 1.51,
"numerator": 51,
"denominator": 100
}
]
},
{
"name": "Draw",
"subType": "D",
"prices": [
{
"decimal": 3.65,
"numerator": 53,
"denominator": 20
}
]
}
]
}
]
}
]
}
}
- site_live_opapstore_soccer.sample.json — trimmed to a few events
- site_pregame_opapstore_soccer.sample.json — trimmed to a few events
- site_pregame_opapstore_basketball.sample.json — money line, point spread and total points, with store codes
Each download is a complete GET /v1/data/{filename} response cut down to a few events, with every id reference still resolving. All samples are listed in samples/index.json.
Extract match-result (1X2) odds in Python
This function is tested against the samples on this page. Pass it the parsed JSON response.
def match_result(payload):
"""(event, 1, X, 2) rows from an OPAP Store (Allwyn) file."""
rows = []
for ev in payload["data"].get("data", {}).get("events", []):
for market in ev.get("markets", []):
if market.get("groupCode") == "MATCH_RESULT":
# outcome subType: H = home, D = draw, A = away (order is not fixed)
odds = {o["subType"]: o["prices"][0]["decimal"] for o in market["outcomes"] if o.get("prices")}
rows.append((ev["name"], odds.get("H"), odds.get("D"), odds.get("A")))
return rows
Fetch OPAP odds
With a direct key
# 1. which files can this key read?
curl -sS --compressed -H "X-API-Key: YOUR_API_KEY" \
https://api.arbplay.app/v1/files
# 2. download one file (JSON envelope: company, file, updated_at, data)
curl -sS --compressed -H "X-API-Key: YOUR_API_KEY" \
https://api.arbplay.app/v1/data/site_pregame_opapstore_soccer.json -o site_pregame_opapstore_soccer.json
import requests # pip install requests
resp = requests.get(
"https://api.arbplay.app/v1/data/site_pregame_opapstore_soccer.json",
headers={"X-API-Key": "YOUR_API_KEY"}, # gzip is negotiated automatically
timeout=60,
)
resp.raise_for_status()
payload = resp.json()
print(payload["updated_at"], payload["file"])
for event, home, draw, away in match_result(payload): # the function above
print(f"{event}: {home} / {draw} / {away}")
// Node 18+ (server-side: the API sends no CORS headers)
const res = await fetch("https://api.arbplay.app/v1/data/site_pregame_opapstore_soccer.json", {
headers: { "X-API-Key": process.env.ARBPLAY_API_KEY },
});
if (!res.ok) throw new Error(`${res.status} ${(await res.json()).detail}`);
const { company, file, updated_at, data } = await res.json();
console.log(file, "updated", updated_at);
Through a marketplace
On RapidAPI, Zyla API Hub or JoJ API you call the marketplace's gateway with that marketplace's key. The two endpoints and the JSON they return are the same; copy the base URL and path from the listing.
| Marketplace | Your key goes in | Base URL and full path |
|---|---|---|
| RapidAPI | X-RapidAPI-Key and X-RapidAPI-Host | Endpoints tab of the listing |
| Zyla API Hub | Authorization: Bearer <access key> | Code sample on the listing |
| JoJ API | X-JoJAPI-Key (or Authorization: Bearer) | Code sample on the listing |
Freshness, gaps and caveats
- Refresh: live files about every 1–3 s, pre-match files about every 4–7 s. Every response carries
updated_atand aLast-Modifiedheader; sendIf-Modified-Sinceto get304 Not Modifiedwhen nothing changed. - Not every event carries every market: many pre-match events list only totals and other markets without a
MATCH_RESULTmarket — checkgroupCode. - The line is part of the market name ("Total Goals Over / Under 2.5").
handicapValueequals the line for totals, but Asian handicaps use quarter-goal units there (a −1.25 line is-5.0) — read the line from the name. - Outcome order inside a market is not fixed — read
subType(H,D,A) instead of the position.
Get OPAP odds API access
- RapidAPI — OPAP odds listing
- Zyla API Hub — OPAP odds listing
- JoJ API — OPAP odds listing
- Contact ArbPlay for a direct key to
https://api.arbplay.app - Before you buy: direct keys for several bookmakers, trial keys, rate limits and data rights
Plans and quotas are set on each marketplace listing. More in the API reference and the API hub.
Frequently asked questions
Is this the official OPAP (Allwyn) API?
No. ArbPlay is independent and is not affiliated with or endorsed by OPAP (Allwyn) or its operator. It collects the odds OPAP (Allwyn) publishes on its public website and serves them unchanged as JSON for informational use. ArbPlay does not place bets.
Why is the OPAP odds API called Allwyn or OPAP Store?
OPAP is part of the Allwyn group, and the files carry the Allwyn store offer, formerly OPAP Store: the odds in Allwyn shops. The marketplace listings are named Allwyn Odds and OPAP Store Odds API; both serve the same files, whose company key is opapstore.
Which OPAP files can I download?
Six: site_live_opapstore_soccer.json, site_live_opapstore_basketball.json, site_live_opapstore_tennis.json and the matching site_pregame_opapstore_*.json files. Call GET /v1/files to list the files your key can read.
How often are OPAP odds updated?
During active hours live files are rewritten about every 1 to 3 seconds and pre-match files about every 4 to 7 seconds. Every response carries updated_at and a Last-Modified header, and If-Modified-Since returns 304 when nothing changed.
Can I match OPAP events with other bookmakers?
Yes. Every event lists a Betradar id in externalIds (provider betradar, value sr:match:<id>). Stoiximan, Novibet, Superbet and Bwin expose the same id, so you can join on it.
How do I get access to the OPAP (Allwyn) odds API?
Subscribe to the OPAP (Allwyn) listing on RapidAPI, Zyla API Hub or JoJ API and call it with that marketplace's key; plans and quotas are set on each listing. For a direct key to https://api.arbplay.app (header X-API-Key), contact ArbPlay.
ArbPlay is independent and not affiliated with or endorsed by OPAP (Allwyn) or its operator. Odds are collected from publicly available bookmaker odds and served unchanged for informational use; ArbPlay does not place bets. 21+.
Other bookmakers: Stoiximan · Novibet · Fonbet · Superbet · Elabet · Bwin. Machine-readable: /openapi.json · /llms.txt. Guide: Greek bookmaker odds API.